package com.example.web.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.web.SysConst;
import com.example.web.dto.*;
import com.example.web.dto.query.*;
import com.example.web.entity.*;
import com.example.web.mapper.*;
import com.example.web.service.*;
import com.example.web.tools.dto.*;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.stream.Collectors;

import lombok.SneakyThrows;
import com.example.web.tools.*;

/**
 * 物品功能实现类
 */
@Service
public class GoodServiceImpl extends ServiceImpl<GoodMapper, Good> implements GoodService {

    /**
     * 操作数据库AppUser表mapper对象
     */
    @Autowired
    private AppUserMapper _AppUserMapper;
    /**
     * 操作数据库的Good表mapper对象
     */
    @Autowired
    private GoodMapper _GoodMpper;


    @Autowired
    private GoodLoveMapper _GoodLoveMapper;


    @Autowired
    private GoodTypeMapper _GoodTypeMapper;


    @Autowired
    private CampusMapper _CampusMapper;
    @Autowired
    private OrderDetailMapper _OrderDetailMapper;

    /**
     * 协同过滤算法推荐
     */
    @SneakyThrows
    @Override
    public PagedResult<GoodDto> Top100(GoodPagedInput input) {
        CurrentUserDto currentUserDto = BaseContext.getCurrentUserDto();

        //如果用户登录了
        if (currentUserDto != null && currentUserDto.getUserId() != null) {
            //协同过滤算法推荐
            CollaborativeFiltering collaborativeFiltering = new CollaborativeFiltering();

            //当前用户id
            Integer userId = currentUserDto.getUserId();

            //获取所有用户
            List<AppUser> AppUserList = _AppUserMapper.selectList(null).stream().toList();
            //只能在指定的校园
            AppUserList = AppUserList.stream().filter(x -> x.getCampusId() == input.getCampusId()).toList();
            //查询订单CampusId等于当前用户的CampusId的订单明细 通过2个表查询
            List<OrderDetail> OrderDetaillist = _OrderDetailMapper.selectList(Wrappers.<OrderDetail>lambdaQuery()
                    .inSql(OrderDetail::getOrderInfoId, "select id from orderinfo where CampusId=" + input.getCampusId())
            ).stream().toList();


            //遍历所有用户
            for (AppUser appUser : AppUserList) {


                //有关联的商品
                int[] RelativeGoodId = OrderDetaillist.stream().filter(x -> x.getCreatorId() == appUser.getId()).mapToInt(x -> x.getGoodId()).distinct().toArray();
                for (int goodId : RelativeGoodId) {
                    //购买次数
                    long buyCount = OrderDetaillist.stream().filter(x -> x.getCreatorId() == appUser.getId() && x.getGoodId() == goodId).count();
                    //添加用户购买次数
                    collaborativeFiltering.AddUserRating(appUser.getId(), goodId, (double) buyCount);
                }

            }

            //用户相似度列表
            List<UserCalculateCosineSimilarity> userCalculateCosineSimilarityList = new ArrayList<>();

            //遍历所有用户
            for (AppUser user2 : AppUserList) {
                //如果相同跳过
                if (userId.equals(user2.getId())) {
                    continue;
                }
                //如果存在跳过
                if (userCalculateCosineSimilarityList.stream().filter(x -> x.getUserId1() == userId && x.getUserId2() == user2.getId()).count() > 0) {
                    continue;
                }
                //如果存在跳过
                if (userCalculateCosineSimilarityList.stream().filter(x -> x.getUserId2() == user2.getId() && x.getUserId1() == userId).count() > 0) {
                    continue;
                }
                //计算相似度
                double v = collaborativeFiltering.CalculateCosineSimilarity(userId, user2.getId());
                //添加到相似度列表
                userCalculateCosineSimilarityList.add(new UserCalculateCosineSimilarity(userId, user2.getId(), v));
            }
            //得到相似的用户
            Collections.sort(userCalculateCosineSimilarityList, new Comparator<UserCalculateCosineSimilarity>() {
                @Override
                public int compare(UserCalculateCosineSimilarity o1, UserCalculateCosineSimilarity o2) {
                    return o2.getSimilarity().compareTo(o1.getSimilarity());
                }
            });
            //取前1000个
            int endIndex = Math.min(1000, userCalculateCosineSimilarityList.size());
            //获取到相似度高的用户
            int[] similarityHighUserId = userCalculateCosineSimilarityList.subList(0, endIndex).stream().mapToInt(x -> x.getUserId2()).toArray();

            //获取到相似度高的用户购买的商品 排除自己
            int[] similarityHighUserIdGoodId = OrderDetaillist.stream().filter(x -> Arrays.binarySearch(similarityHighUserId, x.getCreatorId()) >= 0 && x.getCreatorId() != userId).mapToInt(x -> x.getGoodId()).distinct().toArray();

            //转换成list
            List<Integer> similarityHighUserIdGoodIdList = Arrays.stream(similarityHighUserIdGoodId).boxed().collect(Collectors.toList());

            //随机排序
            Collections.shuffle(similarityHighUserIdGoodIdList);

            //取前10个
            int maxGoodCountEndIndex = Math.min(100, similarityHighUserIdGoodIdList.size());

            //得到10个商品id
            List<Integer> top10GoodIds = similarityHighUserIdGoodIdList.subList(0, maxGoodCountEndIndex);

            if (top10GoodIds.stream().count() < 100) {
                //随机推荐10个商品
                LambdaQueryWrapper<Good> queryWrapper = Wrappers.<Good>lambdaQuery()
                        .orderByDesc(Good::getCreationTime)
                        .last("limit 10");
                List<Good> goods = _GoodMpper.selectList(queryWrapper);
                //只能在指定的校园
                goods = goods.stream().filter(x -> x.getCampusId() == input.getCampusId()).toList();

                List<GoodDto> items = Extension.copyBeanList(goods, GoodDto.class);
                return PagedResult.GetInstance(items, (long) 100);
            }

            //查询出关联的商品信息
            List<Good> goods = _GoodMpper.selectList(null);
            //只能在指定的校园
            goods = goods.stream().filter(x -> x.getCampusId() == input.getCampusId()).toList();

            goods = goods.stream().filter(x -> top10GoodIds.contains(x.getId())).toList();
            List<GoodDto> items = Extension.copyBeanList(goods, GoodDto.class);
            return PagedResult.GetInstance(items, (long) 100);

        } else {
            //随机推荐10个商品
            LambdaQueryWrapper<Good> queryWrapper = Wrappers.<Good>lambdaQuery()
                    .eq(input.getCampusId() != null, Good::getCampusId, input.getCampusId())
                    .orderByDesc(Good::getCreationTime)
                    .last("limit 100");
            List<Good> goods = _GoodMpper.selectList(queryWrapper);
            List<GoodDto> items = Extension.copyBeanList(goods, GoodDto.class);
            return PagedResult.GetInstance(items, (long) 100);
        }

    }

    /**
     * 物品分页查询
     */
    @SneakyThrows
    @Override
    public PagedResult<GoodDto> List(GoodPagedInput input) {


        //声明一个支持物品查询的(拉姆达)表达式
        LambdaQueryWrapper<Good> queryWrapper = Wrappers.<Good>lambdaQuery()
                .eq(input.getId() != null && input.getId() != 0, Good::getId, input.getId())
                .eq(input.getCreatorId() != null, Good::getCreatorId, input.getCreatorId());

        //如果前端搜索传入Name不为空,则进行精模糊搜索
        if (Extension.isNotNullOrEmpty(input.getName())) {
            queryWrapper = queryWrapper.like(Good::getName, input.getName());
        }
        //如果前端搜索传入Unit不为空,则进行精确查询
        if (Extension.isNotNullOrEmpty(input.getUnit())) {
            queryWrapper = queryWrapper.eq(Good::getUnit, input.getUnit());
        }
        //如果前端搜索传入PriceStartRange,则要大于PriceStartRange输入的值
        if (input.getPriceStartRange() != null) {
            queryWrapper = queryWrapper.gt(Good::getPrice, input.getPriceStartRange());
        }
        //如果前端搜索传入PriceEndRange,则要小于PriceEndRange输入的值
        if (input.getPriceEndRange() != null) {
            queryWrapper = queryWrapper.lt(Good::getPrice, input.getPriceEndRange());
        }
        //如果前端搜索传入StockStartRange,则要大于StockStartRange输入的值
        if (input.getStockStartRange() != null) {
            queryWrapper = queryWrapper.gt(Good::getStock, input.getStockStartRange());
        }
        //如果前端搜索传入StockEndRange,则要小于StockEndRange输入的值
        if (input.getStockEndRange() != null) {
            queryWrapper = queryWrapper.lt(Good::getStock, input.getStockEndRange());
        }
        //如果前端搜索传入GoodTypeId不为空,则进行精确查询
        if (input.getGoodTypeId() != null) {
            queryWrapper = queryWrapper.eq(Good::getGoodTypeId, input.getGoodTypeId());
        }
        //如果前端搜索传入CampusId不为空,则进行精确查询
        if (input.getCampusId() != null) {
            queryWrapper = queryWrapper.eq(Good::getCampusId, input.getCampusId());
        }
        //如果前端传入了IsPutaway不为空,则进行精确查询
        if (input.getIsPutaway() != null) {
            queryWrapper = queryWrapper.eq(Good::getIsPutaway, input.getIsPutaway());
        }

        //如果前端传入了IsDraft不为空,则进行精确查询
        if (input.getIsDraft() != null) {
            queryWrapper = queryWrapper.eq(Good::getIsDraft, input.getIsDraft());
        }
        //如果前端传入了AuditStatus不为空,则进行精确查询
        if (input.getAuditStatus() != null) {
            queryWrapper = queryWrapper.eq(Good::getAuditStatus, input.getAuditStatus());
        }

        //按创建时间从大到小排序 最新的显示在最前面
        queryWrapper = queryWrapper.orderByDesc(Good::getCreationTime);
        //构建一个分页查询的model
        Page<Good> page = new Page<>(input.getPage(), input.getLimit());


        //从数据库进行分页查询获取物品数据
        IPage<Good> pageRecords = _GoodMpper.selectPage(page, queryWrapper);

        //获取所有满足条件的数据行数
        Long totalCount = _GoodMpper.selectCount(queryWrapper);

        //把Good实体转换成Good传输模型
        List<GoodDto> items = Extension.copyBeanList(pageRecords.getRecords(), GoodDto.class);
        for (GoodDto item : items) {

            //查询出关联的创建用户信息
            AppUserDto CreatorAppUserDTO = new AppUserDto();
            AppUser CreatorAppUserEntity = _AppUserMapper.selectOne(Wrappers.<AppUser>lambdaQuery().eq(AppUser::getId, item.getCreatorId()));
            if (CreatorAppUserEntity != null) {
                BeanUtils.copyProperties(CreatorAppUserDTO, CreatorAppUserEntity);
                item.setCreatorAppUserDto(CreatorAppUserDTO);
            }


            //查询关联的GoodLove表信息
            List<GoodLove> GoodLoveEntitys = _GoodLoveMapper.selectList(Wrappers.<GoodLove>lambdaQuery().eq(GoodLove::getGoodId, item.getId()));
            List<GoodLoveDto> GoodLoveDTOS = Extension.copyBeanList(GoodLoveEntitys, GoodLoveDto.class);
            item.setGoodLoveDtos(GoodLoveDTOS);


            //查询出关联的GoodType表信息
            GoodTypeDto GoodTypeDTO = new GoodTypeDto();
            GoodType GoodTypeEntity = _GoodTypeMapper.selectOne(Wrappers.<GoodType>lambdaQuery().eq(GoodType::getId, item.getGoodTypeId()));
            if (GoodTypeEntity != null) {
                BeanUtils.copyProperties(GoodTypeDTO, GoodTypeEntity);
                item.setGoodTypeDto(GoodTypeDTO);
            }


            //查询出关联的Campus表信息
            CampusDto CampusDTO = new CampusDto();
            Campus CampusEntity = _CampusMapper.selectOne(Wrappers.<Campus>lambdaQuery().eq(Campus::getId, item.getCampusId()));
            if (CampusEntity != null) {
                BeanUtils.copyProperties(CampusDTO, CampusEntity);
                item.setCampusDto(CampusDTO);
            }

        }

        //返回一个分页结构给前端
        return PagedResult.GetInstance(items, totalCount);

    }

    /**
     * 单个物品查询
     */
    @SneakyThrows
    @Override
    public GoodDto Get(GoodPagedInput input) {
        if (input.getId() == null) {
            return new GoodDto();
        }
        PagedResult<GoodDto> pagedResult = List(input);
        return pagedResult.getTotalCount() > 0 ? pagedResult.getItems().stream().findFirst().get() : new GoodDto();
    }

    /**
     * 物品创建或者修改
     */
    @SneakyThrows
    @Override
    public GoodDto CreateOrEdit(GoodDto input) {

        //声明一个物品实体
        Good Good = new Good();

        //把前端传入的input参数拷贝到物品实体
        BeanUtils.copyProperties(Good, input);

        //调用数据库的增加或者修改方法
        saveOrUpdate(Good);

        //定义一个返回给前端的物品传输模型
        GoodDto GoodDto = new GoodDto();

        //同理把操作的物品实体拷贝给物品传输模型
        BeanUtils.copyProperties(GoodDto, Good);

        //把传输模型返回给前端
        return GoodDto;
    }


}
